package com.easyaop.core;

import com.easyaop.api.Context;
import com.easyaop.api.Events;
import com.easyaop.api.advisor.*;
import com.easyaop.api.event.listener.MethodListener;
import com.easyaop.api.pointcut.MethodPointcut;
import com.easyaop.api.pointcut.Pointcut;
import com.easyaop.core.event.EventSource;
import com.easyaop.core.event.PointcutEvent;

import java.lang.reflect.Method;
import java.util.*;

public class EventsImpl implements Events {
    private static EventsImpl instance = new EventsImpl();

    public static Events getInstance() {
        return instance;
    }

    public void addEventListener(String expression, MethodListener listener) {

        addEventListener(new AspectjExpressionPointcut(expression), listener);
    }

    public void addEventListener(Method method, MethodListener listener) {
        addEventListener(MethodPointcut.of(method), listener);
    }

    public void removeEventListener(String expression, Class<? extends MethodListener> listener) {
        removeEventListener(new AspectjExpressionPointcut(expression), listener);
    }

    public void removeEventListener(Method method, Class<? extends MethodListener> listener) {
        removeEventListener(MethodPointcut.of(method), listener);
    }
//    public <T extends MethodListener> void removeEventListener(Method method, T listener) {
//        removeEventListener(MethodPointcut.of(method),listener);
//    }

    public synchronized void addEventListener(Pointcut pointcut, MethodListener listener) {
        EventAdvisor advisorAdded = Context.addListener(pointcut, listener);
        if (advisorAdded == null) {//如果没添加一个新的advisor，而是只添加了MethodListener
            return;
        }

        EventSource.EVENT_SOURCE.trigger(new PointcutEvent(Collections.singleton(advisorAdded)));
    }

    @Override
    public synchronized boolean removeEventListener(Pointcut pointcut, Class<? extends MethodListener> listener) {
        Optional<Advisor> first = Context.ADVISORS.stream()
                .filter(value -> value instanceof EventAdvisor)
                .filter(pointcut::equals)
                .findFirst();

        if (first.isPresent()) {
            Advisor advisor = first.get();
            ((EventAdvisor) advisor).removeListener(listener);
            return true;
        }
        return false;
    }

}
